﻿using RockBus.Configuration;
using RockBus.Configuration.Interfaces;
using RockBus.DataContracts;
using RockBus.Logging.Interfaces;
using RockBus.Routing.Interfaces;
using RockBus.SubscriptionRepository.Interfaces;
using RockBus.Threading;
using System;
using System.Threading;

namespace RockBus.Routing
{
    public class SubscriptionConfigurationManager : ISubscriptionConfigurationManager, IWithTimerCallback
    {
        public SubscriptionConfigurationManager(
            ILogger logger,
            ISubscriptionRepository subscriptionRepository,
            IInternalConfiguration configuration)
        {
            this.Logger = logger;
            this.SubscriptionRepository = subscriptionRepository;
            this.Configuration = configuration;

            ((IWithTimerCallback)this).ExecuteTimerCallback(null);
            this.InitializationTimer = new Timer(((IWithTimerCallback)this).ExecuteTimerCallback, null, this.Configuration.ReinitializationIntervalMs, this.Configuration.ReinitializationIntervalMs);
        }

        private ILogger Logger { get; set; }

        private ISubscriptionRepository SubscriptionRepository { get; set; }

        private IInternalConfiguration Configuration { get; set; }

        private Timer InitializationTimer { get; set; }

        #region ISubscriptionConfigurationManager

        public SubscriberConfiguration StaticSubscriberConfiguration { get; private set; }

        public PublisherConfiguration StaticPublisherConfiguration { get; private set; }

        public SubscriberConfiguration SubscriberConfiguration { get; private set; }

        public PublisherConfiguration PublisherConfiguration { get; private set; }

        private event EventHandler<SubscriptionConfigurationChangedEventArgs> _onSubscriptionConfigurationChanged;

        public event EventHandler<SubscriptionConfigurationChangedEventArgs> OnSubscriptionConfigurationChanged
        {
            add
            {
                _onSubscriptionConfigurationChanged += value;
                var ea = new SubscriptionConfigurationChangedEventArgs(this.SubscriberConfiguration, this.PublisherConfiguration);
                value.Fire(this, ea);
            }
            remove
            {
                _onSubscriptionConfigurationChanged -= value;
            }
        }

        #endregion ISubscriptionConfigurationManager

        void IWithTimerCallback.ExecuteTimerCallback(object state)
        {
            this.RefreshPublisherConfiguration();
            this.RefreshSubscriberConfiguration();
            this.FireOnSubscriptionConfigurationChanged();
        }

        private void RefreshSubscriberConfiguration()
        {
            SubscriberConfiguration scDefault = null;
            if (null != ServiceBusConfigurationSection.Instance)
            {
                ServiceBusConfigurationSection.Instance.Refresh();
                scDefault = ServiceBusConfigurationSection.Instance.Subscribers.CreateSubscriberConfiguration(true);
                this.StaticSubscriberConfiguration = scDefault;
            }
            else
            {
                this.StaticSubscriberConfiguration = new SubscriberConfiguration();
            }

            SubscriberConfiguration scFromRep = this.SubscriptionRepository.GetSubscriberConfiguration();
            if (null != scFromRep)
            {
                scFromRep.Merge(scDefault);
                this.SubscriberConfiguration = scFromRep;
            }
            else
            {
                this.SubscriberConfiguration = scDefault;
            }
        }

        private void RefreshPublisherConfiguration()
        {
            PublisherConfiguration pcDefault = null;
            if (null != ServiceBusConfigurationSection.Instance)
            {
                ServiceBusConfigurationSection.Instance.Refresh();
                pcDefault = ServiceBusConfigurationSection.Instance.Publishers.CreatePublisherConfiguration();
                this.StaticPublisherConfiguration = pcDefault;
            }
            else
            {
                this.StaticPublisherConfiguration = new PublisherConfiguration();
            }

            PublisherConfiguration pcFromRep = this.SubscriptionRepository.GetPublisherConfiguration();
            if (null != pcFromRep)
            {
                pcFromRep.Merge(pcDefault);
                this.PublisherConfiguration = pcFromRep;
            }
            else
            {
                this.PublisherConfiguration = pcDefault;
            }
        }

        private void FireOnSubscriptionConfigurationChanged()
        {
            var ea = new SubscriptionConfigurationChangedEventArgs(this.SubscriberConfiguration, this.PublisherConfiguration);
            this._onSubscriptionConfigurationChanged.Fire(this, ea);
        }
    }
}